package user_private_key

import (
	"context"
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/hex"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/mr-tron/base58"
	"github.com/pkg/errors"
	"github.com/xinliangnote/go-gin-api/configs"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"strings"
)

func NewModel() *UserPrivateKey {
	return new(UserPrivateKey)
}

func (u *UserPrivateKey) Create(client *mongo.Client) (string, error) {
	cfg := configs.Get().Mongodb
	keyClient := client.Database(cfg.Config.Name).Collection("user_private_key")
	id, err := keyClient.InsertOne(context.TODO(), u)
	return id.InsertedID.(primitive.ObjectID).String(), err
}

func (u *UserPrivateKey) List(client *mongo.Client, pageIndex uint, pageSize uint) (keyList []UserPrivateKey, err error) {
	var list []UserPrivateKey
	cfg := configs.Get().Mongodb
	keyClient := client.Database(cfg.Config.Name).Collection("user_private_key")
	findOptions := options.Find()
	skip := int64((pageIndex - 1) * pageSize)
	findOptions.SetSort(bson.D{{"_id", -1}})
	findOptions.SetSkip(skip)
	findOptions.SetLimit(int64(pageSize))
	filter := bson.M{"userId": u.UserId}
	if u.ChainName != "" {
		filter["chainName"] = strings.ToUpper(u.ChainName)
	}

	if u.CollectAddress != "" {
		filter["collectAddress"] = u.CollectAddress
	}

	find, err := keyClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		return nil, err
	}
	err = find.All(context.TODO(), &list)
	//for k, i := range list {
	//
	//	if i.MainCoinType == 648126 {
	//
	//		feeAddress, err := TRXPrivateToAddress(i.FeeAddress)
	//		if err != nil {
	//			return nil, err
	//		}
	//		list[k].FeeAddress = feeAddress
	//		if i.WithdrawAddress != "" {
	//			withdrawAddress, err := TRXPrivateToAddress(i.WithdrawAddress)
	//			if err != nil {
	//				return nil, err
	//			}
	//			list[k].WithdrawAddress = withdrawAddress
	//		}
	//
	//	} else {
	//		feeAddress, err := PrivateToAddress(i.FeeAddress)
	//		if err != nil {
	//			return nil, err
	//		}
	//		list[k].FeeAddress = feeAddress
	//		if i.WithdrawAddress != "" {
	//			collectionAddress, err := PrivateToAddress(i.WithdrawAddress)
	//			if err != nil {
	//				return nil, err
	//			}
	//			list[k].WithdrawAddress = collectionAddress
	//		}
	//	}
	//
	//}
	return list, nil
}

func (u *UserPrivateKey) GetInfoCount(client *mongo.Client) (bool, error) {
	cfg := configs.Get().Mongodb
	keyClient := client.Database(cfg.Config.Name).Collection("user_private_key")
	count, err := keyClient.CountDocuments(context.TODO(), bson.D{{"userId", u.UserId}, {"chainName", u.ChainName}, {"mainCoinType", u.MainCoinType}})
	return count == 0, err
}

func (u *UserPrivateKey) Update(client *mongo.Client) (err error) {
	cfg := configs.Get().Mongodb
	keyClient := client.Database(cfg.Config.Name).Collection("user_private_key")
	objId, _ := primitive.ObjectIDFromHex(u.Id)
	filter := bson.M{"_id": objId}
	update := bson.M{}
	if u.WithdrawAddress != "" {
		update["withdrawAddress"] = u.WithdrawAddress
	}
	if u.CollectAddress != "" {
		update["collectAddress"] = u.CollectAddress
	}
	if u.FeeAddress != "" {
		update["feeAddress"] = u.FeeAddress
	}
	if len(update) == 0 {
		return nil
	}
	_, err = keyClient.UpdateOne(context.TODO(), filter, bson.M{"$set": update})
	return err
}

func (u *UserPrivateKey) Count(db *mongo.Client) (count int64, err error) {
	cfg := configs.Get().Mongodb
	client := db.Database(cfg.Config.Name).Collection("user_private_key")
	count, err = client.CountDocuments(context.TODO(), bson.D{{"userId", u.UserId}})
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		return 0, err
	}
	return count, nil
}

func (u *UserPrivateKey) Delete(db *mongo.Client, id string) error {
	cfg := configs.Get().Mongodb
	client := db.Database(cfg.Config.Name).Collection("user_private_key")
	objId, _ := primitive.ObjectIDFromHex(id)
	filter := bson.M{"_id": objId}
	_, err := client.DeleteOne(context.TODO(), filter)
	return err
}

func PrivateToAddress(privateKey string) (string, error) {

	priKey, err := crypto.HexToECDSA(privateKey)
	if err != nil {
		return "", err
	}
	//priKeyBytes := crypto.FromECDSA(priKey)
	//fmt.Printf("私钥为: %s\n", hex.EncodeToString(priKeyBytes))

	pubKey := priKey.Public().(*ecdsa.PublicKey)
	// 获取地址
	addr := crypto.PubkeyToAddress(*pubKey)

	return addr.String(), nil

}

func TRXPrivateToAddress(privateKey string) (string, error) {
	priKey, err := crypto.HexToECDSA(privateKey)
	if err != nil {
		return "", err
	}
	publicKey := priKey.Public()
	publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
	addrStr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
	addrStr = "41" + addrStr[2:]
	addb, _ := hex.DecodeString(addrStr)
	firstHash := sha256.Sum256(addb)
	secondHash := sha256.Sum256(firstHash[:])
	secret := secondHash[:4]
	addb = append(addb, secret...)
	address := base58.Encode(addb)
	return address, nil
}
